 /*******************************************************************************
  * Copyright (c) 2007 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
  * http://www.eclipse.org/legal/epl-v10.html
  *
  * Contributors:
  * Benjamin Muskalla - initial API and implementation - https://bugs.eclipse.org/bugs/show_bug.cgi?id=41573
  *******************************************************************************/
 package org.eclipse.ui.texteditor;

 import java.util.ResourceBundle ;

 import org.eclipse.core.runtime.Assert;

 import org.eclipse.jface.viewers.ISelection;
 import org.eclipse.jface.viewers.ISelectionProvider;

 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.ITextSelection;


 /**
  * Action for joining two or more lines together by deleting the
  * line delimiters and trimming the whitespace between them.
  *
  * @since 3.3
  */
 public class JoinLinesAction extends TextEditorAction {

     private String fJoint= null;
     
     
     /**
      * Creates a line joining action.
      *
      * @param bundle the resource bundle for UI strings
      * @param prefix the prefix for the property keys into <code>bundle</code>
      * @param editor the editor
      * @param joint the string to put between the lines
      */
     public JoinLinesAction(ResourceBundle bundle, String prefix, ITextEditor editor, String joint) {
         super(bundle, prefix, editor);
         Assert.isLegal(joint != null);
         fJoint= joint;
         update();
     }

     /*
      * @see org.eclipse.jface.action.Action#run()
      */
     public void run() {
         
         ITextEditor editor= getTextEditor();
         if (editor == null)
             return;

         if (!validateEditorInputState())
             return;

         IDocument document= getDocument(editor);
         if (document == null)
             return;

         ITextSelection selection= getSelection(editor);
         if (selection == null)
             return;

         int startLine= selection.getStartLine();
         int endLine= selection.getEndLine();
         try {
             int caretOffset= joinLines(document, startLine, endLine);
             if (caretOffset > -1)
                 editor.selectAndReveal(caretOffset, 0);
         } catch (BadLocationException e) {
             // should not happen
 }
         
     }

     /**
      * Returns the editor's document.
      *
      * @param editor the editor
      * @return the editor's document
      */
     private static IDocument getDocument(ITextEditor editor) {

         IDocumentProvider documentProvider= editor.getDocumentProvider();
         if (documentProvider == null)
             return null;

         IDocument document= documentProvider.getDocument(editor.getEditorInput());
         if (document == null)
             return null;

         return document;
     }

     /**
      * Returns the editor's selection.
      *
      * @param editor the editor
      * @return the editor's selection
      */
     private static ITextSelection getSelection(ITextEditor editor) {

         ISelectionProvider selectionProvider= editor.getSelectionProvider();
         if (selectionProvider == null)
             return null;

         ISelection selection= selectionProvider.getSelection();
         if (!(selection instanceof ITextSelection))
             return null;

         return (ITextSelection) selection;
     }
     
     /*
      * @see org.eclipse.ui.texteditor.TextEditorAction#update()
      */
     public void update() {
         super.update();
         if (!isEnabled())
             return;

         if (!canModifyEditor()) {
             setEnabled(false);
             return;
         }

         ITextEditor editor= getTextEditor();
         setEnabled(editor.isEditable());
     }
     
     /**
      * Joins several text lines to one line.
      *
      * @param document the document
      * @param startLine the start line
      * @param endLine the end line
      * @return the new caret offset
      * @throws BadLocationException
      */
     private int joinLines(IDocument document, int startLine, int endLine) throws BadLocationException {
         if (startLine == document.getNumberOfLines() - 1) {
             // do nothing because we are in the last line
 return -1;
         }

         if (startLine == endLine)
             endLine++; // append join with the next line

         StringBuffer buffer= new StringBuffer ();
         for (int line= startLine; line <= endLine; line++) {
             buffer.append(trim(document, line, line == startLine));
             if (line != endLine)
                 buffer.append(fJoint);
         }

         int startLineOffset= document.getLineOffset(startLine);
         int endLineOffset= document.getLineOffset(endLine) + document.getLineLength(endLine) - getLineDelimiterLength(document, endLine);
         String replaceString= buffer.toString();
         document.replace(startLineOffset, endLineOffset - startLineOffset, replaceString);
         return startLineOffset + replaceString.length();
     }

     private String trim(IDocument document, int line, boolean ignoreLeadingWhitespace) throws BadLocationException {
         int lineOffset= document.getLineOffset(line);
         int lineLength= document.getLineLength(line);
         lineLength= lineLength - getLineDelimiterLength(document, line);
         if (!ignoreLeadingWhitespace)
             return document.get(lineOffset, lineLength).trim();
         
         while (lineLength > 0 && Character.isWhitespace(document.getChar(lineOffset + lineLength - 1)))
             lineLength--;
         
         return document.get(lineOffset, lineLength);
     }
     
     private int getLineDelimiterLength(IDocument document, int line) throws BadLocationException {
         String lineDelimiter= document.getLineDelimiter(line);
         return lineDelimiter != null ? lineDelimiter.length() : 0;
         
     }

 }

